/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.benchmark.security;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.util.Properties;
import java.util.Vector;

import org.apache.log4j.Logger;

import cgl.narada.discovery.topics.TopicDiscoveryClient;
import cgl.narada.discovery.topics.Topics;
import cgl.narada.discovery.topics.messages.SignedTopicAdvertisement;
import cgl.narada.event.NBEvent;
import cgl.narada.event.TemplateProfileAndSynopsisTypes;
import cgl.narada.matching.Profile;
import cgl.narada.service.ServiceException;
import cgl.narada.service.client.ClientService;
import cgl.narada.service.client.EventConsumer;
import cgl.narada.service.client.NBEventListener;
import cgl.narada.service.client.SessionService;
import cgl.narada.service.qos.ConsumerConstraints;
import cgl.narada.service.security.kmc.KMCClient;
import cgl.narada.service.security.kmc.TopicRights;
import cgl.narada.service.security.kmc.messages.SecureTopicKeyResponse;
import cgl.narada.service.security.securityprovider.CertificateManager;
import cgl.narada.service.security.securityprovider.CertificateUtil;
import cgl.narada.service.timer.ClockI;
import cgl.narada.service.timer.HRClock;

import cgl.narada.mgmt.common.CommandlineArguments;
import cgl.narada.util.SystemInit;
import cgl.narada.util.SystemNotInitializedException;

public class PerfTesterReciever implements NBEventListener {

	static Logger log = Logger.getLogger("PerfTesterReciever");

	static String NB_HOME = "/home/hgadgil/mgmt-jdk1.6/nb-2.0.2/";

	private static String configFilePath = null;

	private static String keystore = null;

	private boolean benchmark = true;

	private static Vector v = new Vector();

	public static void main(String[] a) {
		SystemInit.init();

		try {
			NB_HOME = SystemInit.getInitData(SystemInit.SYS_NB_HOME);
			configFilePath = SystemInit
					.getInitData(SystemInit.SYS_SERVICE_CONFIG_PATH);
			keystore = SystemInit.getInitData(SystemInit.SYS_KEYSTORE);
		} catch (SystemNotInitializedException e3) {
			e3.printStackTrace();
		}

		PerfTesterReciever reciever = new PerfTesterReciever(a);
	}

	public PerfTesterReciever(String[] a) {
		CommandlineArguments cmdLine = new CommandlineArguments(a);

		if (cmdLine.getBooleanProperty("help", false)) {
			System.out.println("java " + PerfTesterReciever.class.getName()
					+ " <options>");
			System.out
					.println(" --host= broker host to use (E.g. --host=gf3.ucs.indiana.edu)");
			System.out
					.println(" --port= broker port to use (E.g. --port=5045)");
			System.out
					.println(" --prot= connection protocol to use (E.g. --prot=tcp)");
			System.out
					.println("\nE.g.: --host=localhost --port=5045 --prot=tcp");
			System.out
					.println("--benchmark (default true): if False,then no measurement data is output ");
			System.out
					.println("--output (default /home/hgadgil/sdr.out): output file for measurements");

			System.exit(0);
		}

		host = cmdLine.getStringProperty("host", "localhost");
		port = cmdLine.getStringProperty("port", "5045");
		prot = cmdLine.getStringProperty("prot", "tcp");
		benchmark = cmdLine.getBooleanProperty("benchmark", true);
		String outputFile = cmdLine.getStringProperty("output",
				"/home/hgadgil/sdr.out");
		System.out.println("Connecting to " + host + ":" + port + " [" + prot
				+ "]");

		x = 0;
		initTopics();

		init();
		if (benchmark) {
			try {
				fout = new FileOutputStream(outputFile);
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
				System.exit(-1);
			}
		}
		ts = HRClock.getClock();
	}

	private String host = "complexity.ucs.indiana.edu";

	private String port = "25010";

	private String prot = "tcp";

	private String topicName = "encrypted";

	private ClockI ts;

	private FileOutputStream fout = null;

	private String topicUUID;

	private EventConsumer consumer;

	private SecureTopicKeyResponse r2;

	private int x;

	private int i;

	private long oldSize = -1;

	public void onEvent(NBEvent nbEvent) {

		if (((String) nbEvent.getContentSynopsis())
				.equals(BenchmarkListener.BENCHMARK_COMMIT)) {
			System.out.println("Committing ...");

			// Now write to file
			if (benchmark) {
				try {
					for (int i = 0; i < v.size(); i++) {
						fout.write(((String) v.elementAt(i) + "\n").getBytes());
					}
					fout.flush();
					fout.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			System.exit(0);
		}

		long tstamp = ts.getTimeMicroseconds();
		long size = nbEvent.getContentPayloadSize();

		if (size != oldSize) {
			i = 1;
			oldSize = size;
			System.out.println("\nGOT Event: " + size);
		} else
			i++;

		v.add((nbEvent.getContentPayloadSize() + ":" + tstamp));
	}

	private void init() {

		// IMP: Might conflict w/ other ppl's entity IDs Maintain constant for
		// now
		int entityId = 51; // (new Random()).nextInt();

		Properties prop = new Properties();

		prop.put("hostname", host);
		prop.put("portnum", port);

		log.info("SecureTopicsManager:- TCP @ " + host + ":" + port
				+ " EntityID[" + entityId + "]");

		try {
			ClientService clientService = SessionService.getClientService(
					entityId, configFilePath);

			System.out.println("Subscribing to : " + topicUUID);

			clientService.initializeBrokerCommunications(prop, prot);

			Profile unSecureprofile = clientService.createProfile(
					TemplateProfileAndSynopsisTypes.STRING, "XYZ");

			Profile secureprofile = clientService.createProfile(
					TemplateProfileAndSynopsisTypes.STRING, topicUUID);

			consumer = clientService.createEventConsumer(this);

			ConsumerConstraints cc = consumer
					.createConsumerConstraints(secureprofile);
			cc.setReceiveSecurely(entityId);
			cc.setSecurityToken(r2.getSignedSecurityToken(), r2.getKey(), null,
					false, rootCA);

			consumer.subscribeTo(secureprofile, cc);
			consumer.subscribeTo(unSecureprofile);

			// Benchmarking
			Profile benchmarkCommit = clientService.createProfile(
					TemplateProfileAndSynopsisTypes.STRING,
					BenchmarkListener.BENCHMARK_COMMIT);
			consumer.subscribeTo(benchmarkCommit);

		} catch (ServiceException e) {
			log.error("", e);
		}
	}

	PublicKey rootCA;

	public void initTopics() {
		CertificateManager certMan = new CertificateManager();
		certMan.init(keystore, "passpass");

		rootCA = CertificateUtil.getPublicKey(certMan, certMan.ROOT_CA_ALIAS);

		Certificate c2_cert = CertificateUtil.getCertificate(certMan, "c2");
		PrivateKey c2_priv = CertificateUtil.getPrivateKey(certMan, "c2");

		// First discover the topic...
		SignedTopicAdvertisement[] stas = discoverTopics(c2_cert, c2_priv,
				topicName, Topics.MATCHING_STRING, 2);

		KMCClient client2 = new KMCClient(c2_cert, c2_priv, rootCA, "/kmc/c2",
				configFilePath, host, port, prot);

		// KMCClient client2 = new KMCClient(c2_cert, c2_priv, rootCA,
		// "/kmc/c2",
		// "c:\\Home\\projects\\NB1rc1\\config\\ServiceConfiguration.txt");

		TopicRights reqRights = new TopicRights(TopicRights.SUBSCRIBE_RIGHT);

		// Now try to get the security token...

		r2 = client2.requestTopicKey(stas[0].getTopicAd().getTopicSynopsis(),
				c2_cert, reqRights, 5000);

		if (r2 == null)
			System.out.println("Request Denied / Timeout occurred !");
		else {
			System.out.println("Sec Token:"
					+ r2.getSignedSecurityToken().getSecurityToken()
							.getValidity().toString());

			topicUUID = stas[0].getTopicAd().getTopicSynopsis();

		}

	}

	public SignedTopicAdvertisement[] discoverTopics(Certificate cert,
			PrivateKey priv, String synopsis, int matchType, int maxTopics) {

		TopicDiscoveryClient disco = new TopicDiscoveryClient(15000,
				configFilePath, cert, priv, host, port, prot);

		// TopicDiscoveryClient disco = new TopicDiscoveryClient(15000,
		// "c:\\Home\\projects\\NB1rc1\\config\\ServiceConfiguration.txt",
		// cert, priv, "localhost", "25000", "niotcp");

		SignedTopicAdvertisement[] stas = disco.discover(matchType, synopsis,
				null, maxTopics);

		disco.close();

		System.out.println("Got: " + stas.length + " SignedTopicAds");

		return stas;
	}
}
